#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Create by zhang
# Create on 2022-11-16 12:47
# -*- coding: utf-8 -*-
from __future__ import annotations
from queue import PriorityQueue, Empty
from threading import *
from time import sleep
from typing import Dict, List

from core.enums import EventType, ThreadName
from core.dataClasses import Event
from core import logger, threadLocal


class EventHandler:
    def __init__(self):
        pass


class EventManager:
    """
    事件管理器
    """

    _instances = {
        "default": None
    }

    @classmethod
    def getInstance(cls, name: str = "default"):
        if name is None:
            name = "default"
        if name not in cls._instances or cls._instances[name] is None:
            cls._instances[name] = cls(name)
        try:
            threadLocal.get(ThreadName.EVENT_MANAGER.value)
        except:
            threadLocal.add(ThreadName.EVENT_MANAGER.value, name)
        return cls._instances[name]

    def __init__(self, name: str, interval: int = 1):
        """
        初始化事件管理器\n
        :param interval: 时钟间隔时间 单位是秒（s）
        """
        self._interval: int = interval
        self._queue = PriorityQueue()
        self._active = False
        """事件管理器开关"""

        self._thread = Thread(target = self._run)
        """事件处理线程"""

        self._timer = Thread(target = self._run_timer)
        """事件处理线程"""

        self.count = 0

        self._handlers: Dict[str, List[EventHandler]] = {}
        """
        这里的__handlers是一个字典，用来保存对应的事件的响应函数
        其中每个键对应的值是一个列表，列表中保存了对该事件监听的响应函数，一对多
        """

    def _run(self):
        """引擎运行"""
        logger.info('{}_run'.format(self.count))
        while self._active:
            try:
                # 获取事件的阻塞时间设为1秒
                event = self._queue.get(block = False, timeout = 1)
                self._eventProcess(event)
            except Empty:
                pass

    def _run_timer(self):
        """时钟运行"""
        logger.info('{}_run'.format(self.count))
        while self._active:
            sleep(self._interval)
            event = Event(EventType.TIMER_UPDATED)
            self.emit(event)

    def _eventProcess(self, event:Event):
        """处理事件"""
        logger.info('{}_EventProcess'.format(self.count))
        # 检查是否存在对该事件进行监听的处理函数
        if event.type.name in self._handlers.keys():
            # 若存在，则按顺序将事件传递给处理函数执行
            for handler in self._handlers[event.type.name]:
                try:
                    handler(event)
                except Exception as e:
                    logger.exception(e)
        self.count += 1

    def start(self):
        """启动"""
        logger.info('{}_Start'.format(self.count))
        # 将事件管理器设为启动
        self._active = True
        # 启动事件处理线程
        self._thread.start()
        self.count += 1

    def stop(self):
        """停止"""
        logger.info('{}_Stop'.format(self.count))
        # 将事件管理器设为停止
        self._active = False
        # 等待事件处理线程退出
        self._thread.join()
        self.count += 1

    def addEventListener(self, eventType: EventType, handler: EventHandler) -> EventManager:
        """绑定事件和监听器处理函数"""
        logger.info('{}_AddEventListener'.format(self.count))
        # 尝试获取该事件类型对应的处理函数列表，若无则创建
        try:
            handlerList = self._handlers[eventType.name]
        except KeyError:
            handlerList = []
            self._handlers[eventType.name] = handlerList
        # 若要注册的处理器不在该事件的处理器列表中，则注册该事件
        if handler not in handlerList:
            handlerList.append(handler)
        logger.info(self._handlers)
        self.count += 1
        return self

    def removeEventListener(self, eventType: EventType, handler) -> EventManager:
        """移除监听器的处理函数"""
        logger.info('{}_RemoveEventListener'.format(self.count))
        try:
            handlerList = self.handlers[eventType.name]
            # 如果该函数存在于列表中，则移除
            if handler in handlerList:
                handlerList.remove(handler)
            # 如果函数列表为空，则从引擎中移除该事件类型
            if not handlerList:
                del self.handlers[eventType.name]
        except KeyError:
            pass
        self.count += 1

    def emit(self, event: Event) -> bool:
        """发送事件，向事件队列中存入事件"""
        self._queue.put(event)
        return True